<?php

/**
 * PPTX Exporter PHP 集成类
 * 基于 pptx-exporter npm 包，为 PPTist 项目提供无界面导出功能
 * 
 * 使用方法：
 * 1. 全局安装: npm install -g pptx-exporter
 * 2. 在PHP中使用此类调用导出功能
 * 
 * 注意：此文件需要放在项目根目录，或者修改路径配置
 */

class PPTXExporter
{
    private $nodePath = 'node';
    private $npmPath = 'npm';
    private $packageName = 'pptx-exporter';
    private $cliPath = 'pptx-exporter'; // CLI命令路径

    /**
     * 构造函数
     * @param string $nodePath Node.js可执行文件路径
     * @param string $npmPath npm可执行文件路径
     * @param string $cliPath pptx-exporter CLI命令路径
     */
    public function __construct($nodePath = 'node', $npmPath = 'npm', $cliPath = 'pptx-exporter')
    {
        $this->nodePath = $nodePath;
        $this->npmPath = $npmPath;
        $this->cliPath = $cliPath;
    }

    /**
     * 检查pptx-exporter是否已安装
     * @return bool
     */
    public function isInstalled()
    {
        // 检查CLI命令是否可用
        $command = sprintf('%s --version', $this->cliPath);
        $output = [];
        exec($command . ' 2>&1', $output, $returnCode);

        if ($returnCode === 0) {
            return true;
        }

        // 检查全局npm包
        $command = sprintf('%s list -g %s', $this->npmPath, $this->packageName);
        $output = [];
        exec($command . ' 2>&1', $output, $returnCode);

        return $returnCode === 0 && !empty($output);
    }

    /**
     * 安装pptx-exporter（如果未安装）
     * @return array
     */
    public function install()
    {
        if ($this->isInstalled()) {
            return ['success' => true, 'message' => 'Already installed'];
        }

        $command = sprintf('%s install -g %s', $this->npmPath, $this->packageName);
        $output = [];
        exec($command . ' 2>&1', $output, $returnCode);

        return [
            'success' => $returnCode === 0,
            'output' => $output,
            'return_code' => $returnCode
        ];
    }

    /**
     * 导出PPTX为文件（使用CLI方式）
     * @param array $pptData PPT数据（PPTist格式）
     * @param string $outputFile 输出文件路径
     * @param bool $compression 是否启用压缩
     * @param callable|null $progressCallback 进度回调函数
     * @return array
     */
    public function exportToFile($pptData, $outputFile, $compression = false, $progressCallback = null)
    {
        // 创建临时JSON文件
        $tempJsonFile = $this->createTempJsonFile($pptData);

        // 构建CLI命令
        $compressionFlag = $compression ? ' -c' : '';
        $verboseFlag = $progressCallback ? ' -V' : '';
        $command = sprintf(
            '%s %s %s%s%s',
            $this->cliPath,
            escapeshellarg($tempJsonFile),
            escapeshellarg($outputFile),
            $compressionFlag,
            $verboseFlag
        );

        $result = $this->executeCommand($command, $progressCallback);

        // 清理临时文件
        $this->cleanupTempFile($tempJsonFile);

        return $result;
    }

    /**
     * 导出PPTX为Base64字符串
     * @param array $pptData PPT数据（PPTist格式）
     * @param bool $compression 是否启用压缩
     * @return array
     */
    public function exportToBase64($pptData, $compression = false)
    {
        // 创建临时JSON文件
        $tempJsonFile = $this->createTempJsonFile($pptData);

        // 使用CLI命令导出到临时文件，然后读取并转换为Base64
        $tempPptxFile = tempnam(sys_get_temp_dir(), 'ppt_output_') . '.pptx';

        $compressionFlag = $compression ? ' -c' : '';
        $command = sprintf(
            '%s %s %s%s',
            $this->cliPath,
            escapeshellarg($tempJsonFile),
            escapeshellarg($tempPptxFile),
            $compressionFlag
        );

        $result = $this->executeCommand($command);

        // 清理临时JSON文件
        $this->cleanupTempFile($tempJsonFile);

        if ($result['success'] && file_exists($tempPptxFile)) {
            // 读取文件并转换为Base64
            $base64 = base64_encode(file_get_contents($tempPptxFile));
            $this->cleanupTempFile($tempPptxFile);

            return [
                'success' => true,
                'base64' => $base64
            ];
        }

        // 清理临时文件
        $this->cleanupTempFile($tempPptxFile);

        return [
            'success' => false,
            'error' => 'Failed to export to base64',
            'output' => $result['output']
        ];
    }

    /**
     * 导出PPTX为Buffer（Base64编码）
     * @param array $pptData PPT数据（PPTist格式）
     * @param bool $compression 是否启用压缩
     * @return array
     */
    public function exportToBuffer($pptData, $compression = false)
    {
        // 直接调用exportToBase64，结果是一样的
        return $this->exportToBase64($pptData, $compression);
    }

    /**
     * 智能导出（自动选择最佳格式）
     * @param array $pptData PPT数据（PPTist格式）
     * @param bool $compression 是否启用压缩
     * @return array
     */
    public function smartExport($pptData, $compression = false)
    {
        // 在PHP环境中，智能导出默认返回Base64格式
        $base64Result = $this->exportToBase64($pptData, $compression);

        if ($base64Result['success']) {
            return [
                'success' => true,
                'data' => [
                    'format' => 'base64',
                    'data' => $base64Result['base64']
                ]
            ];
        }

        return $base64Result;
    }

    /**
     * 获取环境信息
     * @return array
     */
    public function getEnvironment()
    {
        // 在PHP环境中，返回固定的环境信息
        return [
            'success' => true,
            'environment' => [
                'environment' => 'node',
                'formats' => ['file', 'base64', 'buffer']
            ]
        ];
    }

    /**
     * 创建临时JSON文件
     * @param array $data
     * @return string 文件路径
     */
    private function createTempJsonFile($data)
    {
        $tempFile = tempnam(sys_get_temp_dir(), 'ppt_data_') . '.json';
        file_put_contents($tempFile, json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
        return $tempFile;
    }

    /**
     * 清理临时文件
     * @param string $filePath
     */
    private function cleanupTempFile($filePath)
    {
        if (file_exists($filePath)) {
            unlink($filePath);
        }
    }

    /**
     * 执行命令
     * @param string $command
     * @param callable|null $progressCallback 进度回调函数
     * @return array
     */
    private function executeCommand($command, $progressCallback = null)
    {
        $output = [];
        $returnCode = 0;

        if ($progressCallback) {
            // 使用proc_open来实时获取输出
            $descriptorspec = [
                0 => ['pipe', 'r'],  // stdin
                1 => ['pipe', 'w'],  // stdout
                2 => ['pipe', 'w']   // stderr
            ];

            $process = proc_open($command, $descriptorspec, $pipes);

            if (is_resource($process)) {
                // 关闭stdin
                fclose($pipes[0]);

                // 读取stdout和stderr
                while (($line = fgets($pipes[1])) !== false || ($errorLine = fgets($pipes[2])) !== false) {
                    if ($line !== false) {
                        $output[] = trim($line);
                        // 尝试解析进度信息
                        if (preg_match('/\[.*?\] (\d+)% \| .*? \| (\d+)\/(\d+) 张幻灯片/', $line, $matches)) {
                            $percentage = (int)$matches[1];
                            $current = (int)$matches[2];
                            $total = (int)$matches[3];
                            $completed = strpos($line, '✅ 完成') !== false;

                            call_user_func($progressCallback, [
                                'current' => $current,
                                'total' => $total,
                                'percentage' => $percentage,
                                'completed' => $completed
                            ]);
                        }
                    }
                    if ($errorLine !== false) {
                        $output[] = trim($errorLine);
                    }
                }

                fclose($pipes[1]);
                fclose($pipes[2]);
                $returnCode = proc_close($process);
            }
        } else {
            // 使用简单的exec
            exec($command . ' 2>&1', $output, $returnCode);
        }

        return [
            'success' => $returnCode === 0,
            'output' => $output,
            'return_code' => $returnCode,
            'command' => $command
        ];
    }
}

// 使用示例
if (basename(__FILE__) === basename($_SERVER['SCRIPT_NAME'])) {
    echo "=== PPTX Exporter PHP 集成示例 ===\n\n";

    // 创建导出器实例
    $exporter = new PPTXExporter();

    // 检查安装状态
    echo "检查 pptx-exporter 安装状态...\n";
    if (!$exporter->isInstalled()) {
        echo "pptx-exporter 未安装，正在安装...\n";
        $installResult = $exporter->install();
        if (!$installResult['success']) {
            echo "安装失败：" . implode("\n", $installResult['output']) . "\n";
            exit(1);
        }
        echo "安装成功！\n";
    } else {
        echo "pptx-exporter 已安装\n";
    }

    // 获取环境信息
    echo "\n获取环境信息...\n";
    $envResult = $exporter->getEnvironment();
    if ($envResult['success']) {
        echo "当前环境: " . $envResult['environment']['environment'] . "\n";
        echo "支持的格式: " . implode(', ', $envResult['environment']['formats']) . "\n";
    }

    // PPTist 格式的演示数据
    $pptData = [
        'title' => 'PHP集成演示',
        'width' => 960,
        'height' => 540,
        'theme' => [
            'backgroundColor' => '#ffffff',
        ],
        'slides' => [
            [
                'elements' => [
                    [
                        'type' => 'text',
                        'content' => '<p>欢迎使用 PPTX Exporter PHP 集成</p>',
                        'x' => 100,
                        'y' => 100,
                        'width' => 760,
                        'height' => 80,
                        'fontSize' => 32,
                        'fontWeight' => 'bold',
                        'color' => '#333333',
                        'textAlign' => 'center',
                    ],
                    [
                        'type' => 'text',
                        'content' => '<p>基于 PPTist 项目开发</p>',
                        'x' => 100,
                        'y' => 200,
                        'width' => 760,
                        'height' => 60,
                        'fontSize' => 24,
                        'color' => '#666666',
                        'textAlign' => 'center',
                    ]
                ]
            ]
        ]
    ];

    // 测试导出为文件（带进度追踪）
    echo "\n测试导出为文件（带进度追踪）...\n";
    $fileResult = $exporter->exportToFile($pptData, './php-demo.pptx', true, function ($progress) {
        $barLength = 30;
        $filledLength = round(($progress['percentage'] / 100) * $barLength);
        $bar = str_repeat('█', $filledLength) . str_repeat('░', $barLength - $filledLength);

        echo "\r[{$bar}] {$progress['percentage']}% | {$progress['current']}/{$progress['total']} 张幻灯片";

        if ($progress['completed']) {
            echo " | ✅ 完成\n";
        }
    });

    if ($fileResult['success']) {
        echo "✅ 文件导出成功：./php-demo.pptx\n";
    } else {
        echo "❌ 文件导出失败：" . implode("\n", $fileResult['output']) . "\n";
    }

    // 测试导出为Base64
    echo "\n测试导出为Base64...\n";
    $base64Result = $exporter->exportToBase64($pptData, true);
    if ($base64Result['success']) {
        echo "✅ Base64导出成功，长度：" . strlen($base64Result['base64']) . " 字符\n";
        echo "前100字符：" . substr($base64Result['base64'], 0, 100) . "...\n";
    } else {
        echo "❌ Base64导出失败：\n";
        echo "错误信息：" . (isset($base64Result['error']) ? $base64Result['error'] : 'Unknown error') . "\n";
        echo "输出详情：" . implode("\n", $base64Result['output']) . "\n";
        echo "执行的命令：" . (isset($base64Result['command']) ? $base64Result['command'] : 'N/A') . "\n";
    }

    // 测试智能导出
    echo "\n测试智能导出...\n";
    $smartResult = $exporter->smartExport($pptData, true);
    if ($smartResult['success']) {
        echo "✅ 智能导出成功\n";
        if (isset($smartResult['data']['format'])) {
            echo "导出格式：" . $smartResult['data']['format'] . "\n";
            if (isset($smartResult['data']['data']) && is_string($smartResult['data']['data'])) {
                echo "数据长度：" . strlen($smartResult['data']['data']) . " 字符\n";
            }
        } else {
            echo "智能导出数据：" . json_encode($smartResult['data']) . "\n";
        }
    } else {
        echo "❌ 智能导出失败：" . implode("\n", $smartResult['output']) . "\n";
    }

    echo "\n=== 测试完成 ===\n";
}
